using System.Diagnostics;
using System.Text;
using Community.CsharpSqlite.Entity;

namespace Community.CsharpSqlite
{
    public  class Tokenize
    {
        /*
    ** 2001 September 15
    **
    ** The author disclaims copyright to this source code.  In place of
    ** a legal notice, here is a blessing:
    **
    **    May you do good and not evil.
    **    May you find forgiveness for yourself and forgive others.
    **    May you share freely, never taking more than you give.
    **
    *************************************************************************
    ** An tokenizer for SQL
    **
    ** This file contains C code that splits an SQL input string up into
    ** individual tokens and sends those tokens one-by-one over to the
    ** parser for analysis.
    *************************************************************************
    **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
    **  C#-SQLite is an independent reimplementation of the SQLite software library
    **
    **  SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d
    **
    **  $Header: Community.CsharpSqlite/src/tokenize_c.cs,v 6604176a7dbe 2010/03/12 23:35:36 Noah $
    *************************************************************************
    */
        //#include "sqliteInt.h"
        //#include <stdlib.h>

        /*
    ** The charMap() macro maps alphabetic characters into their
    ** lower-case ASCII equivalent.  On ASCII machines, this is just
    ** an upper-to-lower case map.  On EBCDIC machines we also need
    ** to adjust the encoding.  Only alphabetic characters and underscores
    ** need to be translated.
    */
#if SQLITE_ASCII
        //# define charMap(X) Global.Sqlite3UpperToLower[(unsigned char)X]
#endif
#if SQLITE_EBCDIC
//# define charMap(X) ebcdicToAscii[(unsigned char)X]
//const unsigned char ebcdicToAscii[] = {
/* 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 0x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 1x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 2x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 3x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 4x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 5x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 95,  0,  0,  /* 6x */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* 7x */
//   0, 97, 98, 99,100,101,102,103,104,105,  0,  0,  0,  0,  0,  0,  /* 8x */
//   0,106,107,108,109,110,111,112,113,114,  0,  0,  0,  0,  0,  0,  /* 9x */
//   0,  0,115,116,117,118,119,120,121,122,  0,  0,  0,  0,  0,  0,  /* Ax */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* Bx */
//   0, 97, 98, 99,100,101,102,103,104,105,  0,  0,  0,  0,  0,  0,  /* Cx */
//   0,106,107,108,109,110,111,112,113,114,  0,  0,  0,  0,  0,  0,  /* Dx */
//   0,  0,115,116,117,118,119,120,121,122,  0,  0,  0,  0,  0,  0,  /* Ex */
//   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  /* Fx */
//};
#endif

        /*
** The KeywordHash.KeywordCode function looks up an identifier to determine if
** it is a keyword.  If it is a keyword, the token code of that keyword is
** returned.  If the input is not a keyword, TokenKeyword.TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
*/
        //#include "keywordhash.h"


        /*
    ** If X is a character that can be used in an identifier then
    ** Complete.IdChar(X) will be true.  Otherwise it is false.
    **
    ** For ASCII, any character with the high-order bit set is
    ** allowed in an identifier.  For 7-bit characters,
    ** sqlite3IsIdChar[X] must be 1.
    **
    ** For EBCDIC, the rules are more complex but have the same
    ** end result.
    **
    ** Ticket #1066.  the SQL standard does not allow '$' in the
    ** middle of identfiers.  But many SQL implementations do.
    ** SQLite will allow '$' in identifiers for compatibility.
    ** But the feature is undocumented.
    */
#if SQLITE_ASCII
        //#define Complete.IdChar(C)  ((Global.Sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
#endif
#if SQLITE_EBCDIC
//const char sqlite3IsEbcdicIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
//    0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 4x */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0,  /* 5x */
//    0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,  /* 6x */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,  /* 7x */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0,  /* 8x */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0,  /* 9x */
//    1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0,  /* Ax */
//    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* Bx */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,  /* Cx */
//    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,  /* Dx */
//    0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,  /* Ex */
//    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0,  /* Fx */
//};
//#define Complete.IdChar(C)  (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif



        /// <summary>
        ///  Return the length of the token that begins at z[iOffset + 0].
        ///  Store the token type in *tokenType before returning.
        /// </summary>
        /// <param name="z"></param>
        /// <param name="iOffset"></param>
        /// <param name="tokenType"></param>
        /// <returns></returns>
        public static int GetToken(string z, int iOffset, ref int tokenType)
        {
            int i;
            byte c = 0;
            switch (z[iOffset + 0])
            {
                case ' ':
                case '\t':
                case '\n':
                case '\f':
                case '\r':
                    {
                        UnitTest.TestCase(z[iOffset + 0] == ' ');
                        UnitTest.TestCase(z[iOffset + 0] == '\t');
                        UnitTest.TestCase(z[iOffset + 0] == '\n');
                        UnitTest.TestCase(z[iOffset + 0] == '\f');
                        UnitTest.TestCase(z[iOffset + 0] == '\r');
                        for (i = 1; z.Length > iOffset + i && SqliteInt.Sqlite3Isspace(z[iOffset + i]); i++)
                        {
                        }
                        tokenType = TokenKeyword.TK_SPACE;
                        return i;
                    }
                case '-':
                    {
                        if (z.Length > iOffset + 1 && z[iOffset + 1] == '-')
                        {
                            /* IMP: R-15891-05542 -- syntax diagram for comments */
                            for (i = 2; z.Length > iOffset + i && (c = (byte) z[iOffset + i]) != 0 && c != '\n'; i++)
                            {
                            }
                            tokenType = TokenKeyword.TK_SPACE; /* IMP: R-22934-25134 */
                            return i;
                        }
                        tokenType = TokenKeyword.TK_MINUS;
                        return 1;
                    }
                case '(':
                    {
                        tokenType = TokenKeyword.TK_LP;
                        return 1;
                    }
                case ')':
                    {
                        tokenType = TokenKeyword.TK_RP;
                        return 1;
                    }
                case ';':
                    {
                        tokenType = TokenKeyword.TK_SEMI;
                        return 1;
                    }
                case '+':
                    {
                        tokenType = TokenKeyword.TK_PLUS;
                        return 1;
                    }
                case '*':
                    {
                        tokenType = TokenKeyword.TK_STAR;
                        return 1;
                    }
                case '/':
                    {
                        if (iOffset + 2 >= z.Length || z[iOffset + 1] != '*')
                        {
                            tokenType = TokenKeyword.TK_SLASH;
                            return 1;
                        }
                        /* IMP: R-15891-05542 -- syntax diagram for comments */
                        for (i = 3, c = (byte) z[iOffset + 2];
                             iOffset + i < z.Length && (c != '*' || (z[iOffset + i] != '/') && (c != 0));
                             i++)
                        {
                            c = (byte) z[iOffset + i];
                        }
                        if (iOffset + i == z.Length) c = 0;
                        if (c != 0) i++;
                        tokenType = TokenKeyword.TK_SPACE; /* IMP: R-22934-25134 */
                        return i;
                    }
                case '%':
                    {
                        tokenType = TokenKeyword.TK_REM;
                        return 1;
                    }
                case '=':
                    {
                        tokenType = TokenKeyword.TK_EQ;
                        return 1 + (z[iOffset + 1] == '=' ? 1 : 0);
                    }
                case '<':
                    {
                        if ((c = (byte) z[iOffset + 1]) == '=')
                        {
                            tokenType = TokenKeyword.TK_LE;
                            return 2;
                        }
                        else if (c == '>')
                        {
                            tokenType = TokenKeyword.TK_NE;
                            return 2;
                        }
                        else if (c == '<')
                        {
                            tokenType = TokenKeyword.TK_LSHIFT;
                            return 2;
                        }
                        else
                        {
                            tokenType = TokenKeyword.TK_LT;
                            return 1;
                        }
                    }
                case '>':
                    {
                        if (z.Length > iOffset + 1 && (c = (byte) z[iOffset + 1]) == '=')
                        {
                            tokenType = TokenKeyword.TK_GE;
                            return 2;
                        }
                        else if (c == '>')
                        {
                            tokenType = TokenKeyword.TK_RSHIFT;
                            return 2;
                        }
                        else
                        {
                            tokenType = TokenKeyword.TK_GT;
                            return 1;
                        }
                    }
                case '!':
                    {
                        if (z[iOffset + 1] != '=')
                        {
                            tokenType = TokenKeyword.TK_ILLEGAL;
                            return 2;
                        }
                        else
                        {
                            tokenType = TokenKeyword.TK_NE;
                            return 2;
                        }
                    }
                case '|':
                    {
                        if (z[iOffset + 1] != '|')
                        {
                            tokenType = TokenKeyword.TK_BITOR;
                            return 1;
                        }
                        else
                        {
                            tokenType = TokenKeyword.TK_CONCAT;
                            return 2;
                        }
                    }
                case ',':
                    {
                        tokenType = TokenKeyword.TK_COMMA;
                        return 1;
                    }
                case '&':
                    {
                        tokenType = TokenKeyword.TK_BITAND;
                        return 1;
                    }
                case '~':
                    {
                        tokenType = TokenKeyword.TK_BITNOT;
                        return 1;
                    }
                case '`':
                case '\'':
                case '"':
                    {
                        int delim = z[iOffset + 0];
                        UnitTest.TestCase(delim == '`');
                        UnitTest.TestCase(delim == '\'');
                        UnitTest.TestCase(delim == '"');
                        for (i = 1; (iOffset + i) < z.Length && (c = (byte) z[iOffset + i]) != 0; i++)
                        {
                            if (c == delim)
                            {
                                if (z.Length > iOffset + i + 1 && z[iOffset + i + 1] == delim)
                                {
                                    i++;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        if ((iOffset + i == z.Length && c != delim) || z[iOffset + i] != delim)
                        {
                            tokenType = TokenKeyword.TK_ILLEGAL;
                            return i + 1;
                        }
                        if (c == '\'')
                        {
                            tokenType = TokenKeyword.TK_STRING;
                            return i + 1;
                        }
                        else if (c != 0)
                        {
                            tokenType = TokenKeyword.TK_ID;
                            return i + 1;
                        }
                        else
                        {
                            tokenType = TokenKeyword.TK_ILLEGAL;
                            return i;
                        }
                    }
                case '.':
                    {
#if !SQLITE_OMIT_FLOATING_POINT
                        if (!SqliteInt.Sqlite3Isdigit(z[iOffset + 1]))
#endif
                        {
                            tokenType = TokenKeyword.TK_DOT;
                            return 1;
                        }
                        /* If the next character is a digit, this is a floating point
            ** number that begins with ".".  Fall thru into the next case */
                        goto case '0';
                    }
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    {
                        UnitTest.TestCase(z[iOffset] == '0');
                        UnitTest.TestCase(z[iOffset] == '1');
                        UnitTest.TestCase(z[iOffset] == '2');
                        UnitTest.TestCase(z[iOffset] == '3');
                        UnitTest.TestCase(z[iOffset] == '4');
                        UnitTest.TestCase(z[iOffset] == '5');
                        UnitTest.TestCase(z[iOffset] == '6');
                        UnitTest.TestCase(z[iOffset] == '7');
                        UnitTest.TestCase(z[iOffset] == '8');
                        UnitTest.TestCase(z[iOffset] == '9');
                        tokenType = TokenKeyword.TK_INTEGER;
                        for (i = 0; z.Length > iOffset + i && SqliteInt.Sqlite3Isdigit(z[iOffset + i]); i++)
                        {
                        }
#if !SQLITE_OMIT_FLOATING_POINT
                        if (z.Length > iOffset + i && z[iOffset + i] == '.')
                        {
                            i++;
                            while (z.Length > iOffset + i && SqliteInt.Sqlite3Isdigit(z[iOffset + i]))
                            {
                                i++;
                            }
                            tokenType = TokenKeyword.TK_FLOAT;
                        }
                        if (z.Length > iOffset + i + 1 && (z[iOffset + i] == 'e' || z[iOffset + i] == 'E') &&
                            (SqliteInt.Sqlite3Isdigit(z[iOffset + i + 1])
                             ||
                             z.Length > iOffset + i + 2 &&
                             ((z[iOffset + i + 1] == '+' || z[iOffset + i + 1] == '-') &&
                              SqliteInt.Sqlite3Isdigit(z[iOffset + i + 2]))
                            )
                            )
                        {
                            i += 2;
                            while (z.Length > iOffset + i && SqliteInt.Sqlite3Isdigit(z[iOffset + i]))
                            {
                                i++;
                            }
                            tokenType = TokenKeyword.TK_FLOAT;
                        }
#endif
                        while (iOffset + i < z.Length && Complete.IdChar((byte) z[iOffset + i]))
                        {
                            tokenType = TokenKeyword.TK_ILLEGAL;
                            i++;
                        }
                        return i;
                    }

                case '[':
                    {
                        for (i = 1, c = (byte) z[iOffset + 0];
                             c != ']' && (iOffset + i) < z.Length && (c = (byte) z[iOffset + i]) != 0;
                             i++)
                        {
                        }
                        tokenType = c == ']' ? TokenKeyword.TK_ID : TokenKeyword.TK_ILLEGAL;
                        return i;
                    }
                case '?':
                    {
                        tokenType = TokenKeyword.TK_VARIABLE;
                        for (i = 1; z.Length > iOffset + i && SqliteInt.Sqlite3Isdigit(z[iOffset + i]); i++)
                        {
                        }
                        return i;
                    }
                case '#':
                    {
                        for (i = 1; z.Length > iOffset + i && SqliteInt.Sqlite3Isdigit(z[iOffset + i]); i++)
                        {
                        }
                        if (i > 1)
                        {
                            /* Parameters of the form #NNN (where NNN is a number) are used
              ** internally by Build.NestedParse.  */
                            tokenType = TokenKeyword.TK_REGISTER;
                            return i;
                        }
                        /* Fall through into the next case if the '#' is not followed by
            ** a digit. Try to match #AAAA where AAAA is a parameter name. */
                        goto case ':';
                    }
#if !SQLITE_OMIT_TCL_VARIABLE
                case '$':
#endif
                case '@': /* For compatibility with MS SQL Server */
                case ':':
                    {
                        int n = 0;
                        UnitTest.TestCase(z[iOffset + 0] == '$');
                        UnitTest.TestCase(z[iOffset + 0] == '@');
                        UnitTest.TestCase(z[iOffset + 0] == ':');
                        tokenType = TokenKeyword.TK_VARIABLE;
                        for (i = 1; z.Length > iOffset + i && (c = (byte) z[iOffset + i]) != 0; i++)
                        {
                            if (Complete.IdChar(c))
                            {
                                n++;
#if !SQLITE_OMIT_TCL_VARIABLE
                            }
                            else if (c == '(' && n > 0)
                            {
                                do
                                {
                                    i++;
                                } while ((iOffset + i) < z.Length && (c = (byte) z[iOffset + i]) != 0 &&
                                         !SqliteInt.Sqlite3Isspace(c) && c != ')');
                                if (c == ')')
                                {
                                    i++;
                                }
                                else
                                {
                                    tokenType = TokenKeyword.TK_ILLEGAL;
                                }
                                break;
                            }
                            else if (c == ':' && z[iOffset + i + 1] == ':')
                            {
                                i++;
#endif
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (n == 0) tokenType = TokenKeyword.TK_ILLEGAL;
                        return i;
                    }
#if !SQLITE_OMIT_BLOB_LITERAL
                case 'x':
                case 'X':
                    {
                        UnitTest.TestCase(z[iOffset + 0] == 'x');
                        UnitTest.TestCase(z[iOffset + 0] == 'X');
                        if (z.Length > iOffset + 1 && z[iOffset + 1] == '\'')
                        {
                            tokenType = TokenKeyword.TK_BLOB;
                            for (i = 2; z.Length > iOffset + i && (c = (byte) z[iOffset + i]) != 0 && c != '\''; i++)
                            {
                                if (!SqliteInt.Sqlite3Isxdigit(c))
                                {
                                    tokenType = TokenKeyword.TK_ILLEGAL;
                                }
                            }
                            if (i%2 != 0 || z.Length == iOffset + i && c != '\'') tokenType = TokenKeyword.TK_ILLEGAL;
                            if (c != 0) i++;
                            return i;
                        }
                        goto default;
                        /* Otherwise fall through to the next case */
                    }
#endif
                default:
                    {
                        if (!Complete.IdChar((byte) z[iOffset]))
                        {
                            break;
                        }
                        for (i = 1; i < z.Length - iOffset && Complete.IdChar((byte) z[iOffset + i]); i++)
                        {
                        }
                        tokenType = KeywordHash.KeywordCode(z, iOffset, i);
                        return i;
                    }
            }
            tokenType = TokenKeyword.TK_ILLEGAL;
            return 1;
        }


        /// <summary>
        ///  Run the parser on the given SQL string.  The parser structure is
        ///  passed in.  An SQLITE_ status code is returned.  If an error occurs
        ///  then an and attempt is made to write an error message into
        ///  memory obtained from Malloc.sqlite3_malloc() and to make pzErrMsg point to that
        ///  error message.
        /// </summary>
        public static int RunParser(Parse pParse, string zSql, ref string pzErrMsg)
        {
            int nErr = 0; /* Number of errors encountered */
            int i; /* Loop counter */
            yyParser pEngine; /* The LEMON-generated LALR(1) parser */
            int tokenType = 0; /* type of the next token */
            int lastTokenParsed = -1; /* type of the previous token */
            byte enableLookaside; /* Saved value of db->lookaside.bEnabled */
            sqlite3 db = pParse.db; /* The database connection */
            int mxSqlLen; /* Max length of an SQL string */


            mxSqlLen = db.aLimit[LimitCategory.SQLITE_LIMIT_SQL_LENGTH];
            if (db.activeVdbeCnt == 0)
            {
                db.u1.isInterrupted = false;
            }
            pParse.rc = StatusCode.SQLITE_OK;
            pParse.zTail = new StringBuilder(zSql);
            i = 0;
            Debug.Assert(pzErrMsg != null);
            pEngine = Parser.sqlite3ParserAlloc(); //sqlite3ParserAlloc((void*(*)(size_t))Malloc.sqlite3Malloc);
            if (pEngine == null)
            {
                ////        db.mallocFailed = 1;
                return StatusCode.SQLITE_NOMEM;
            }
            Debug.Assert(pParse.pNewTable == null);
            Debug.Assert(pParse.pNewTrigger == null);
            Debug.Assert(pParse.nVar == 0);
            Debug.Assert(pParse.nVarExpr == 0);
            Debug.Assert(pParse.nVarExprAlloc == 0);
            Debug.Assert(pParse.apVarExpr == null);
            enableLookaside = db.lookaside.bEnabled;
            if (db.lookaside.pStart != 0) db.lookaside.bEnabled = 1;
            while ( /*  0 == db.mallocFailed && */  i < zSql.Length)
            {
                Debug.Assert(i >= 0);
                //pParse->sLastToken.z = &zSql[i];
                pParse.sLastToken.n = Tokenize.GetToken(zSql, i, ref tokenType);
                pParse.sLastToken.z = zSql.Substring(i);
                i += pParse.sLastToken.n;
                if (i > mxSqlLen)
                {
                    pParse.rc = StatusCode.SQLITE_TOOBIG;
                    break;
                }
                switch (tokenType)
                {
                    case TokenKeyword.TK_SPACE:
                        {
                            if (db.u1.isInterrupted)
                            {
                                Utility.Sqlite3ErrorMsg(pParse, "interrupt");
                                pParse.rc = StatusCode.SQLITE_INTERRUPT;
                                goto abort_parse;
                            }
                            break;
                        }
                    case TokenKeyword.TK_ILLEGAL:
                        {
                            MemPool.DbFree(db, ref pzErrMsg);
                            pzErrMsg = Print.MPrintf(db, "unrecognized token: \"%T\"",
                                                      (object) pParse.sLastToken);
                            nErr++;
                            goto abort_parse;
                        }
                    case TokenKeyword.TK_SEMI:
                        {
                            //pParse.zTail = new StringBuilder(zSql.Substring( i,zSql.Length-i ));
                            /* Fall thru into the default case */
                            goto default;
                        }
                    default:
                        {
                            Parser.sqlite3Parser(pEngine, tokenType, pParse.sLastToken, pParse);
                            lastTokenParsed = tokenType;
                            if (pParse.rc != StatusCode.SQLITE_OK)
                            {
                                goto abort_parse;
                            }
                            break;
                        }
                }
            }
            abort_parse:
            pParse.zTail = new StringBuilder(zSql.Length <= i ? "" : zSql.Substring(i, zSql.Length - i));
            if (zSql.Length >= i && nErr == 0 && pParse.rc == StatusCode.SQLITE_OK)
            {
                if (lastTokenParsed != TokenKeyword.TK_SEMI)
                {
                    Parser.sqlite3Parser(pEngine, TokenKeyword.TK_SEMI, pParse.sLastToken, pParse);
                }
                Parser.sqlite3Parser(pEngine, 0, pParse.sLastToken, pParse);
            }
#if YYTRACKMAXSTACKDEPTH
StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
#endif
            //* YYDEBUG */
            Parser.sqlite3ParserFree(pEngine, null); //Malloc.sqlite3_free );
            db.lookaside.bEnabled = enableLookaside;
            //if ( db.mallocFailed != 0 )
            //{
            //  pParse.rc = StatusCode.SQLITE_NOMEM;
            //}
            if (pParse.rc != StatusCode.SQLITE_OK && pParse.rc != StatusCode.SQLITE_DONE && pParse.zErrMsg == "")
            {
               Malloc.SetString(ref pParse.zErrMsg, db, Utility.ErrorString(pParse.rc));
            }
            //assert( pzErrMsg!=0 );
            if (pParse.zErrMsg != null)
            {
                pzErrMsg = pParse.zErrMsg;
                Print.Sqlite3_log(pParse.rc, "%s", pzErrMsg);
                pParse.zErrMsg = "";
                nErr++;
            }
            if (pParse.pVdbe != null && pParse.nErr > 0 && pParse.nested == 0)
            {
               VdbeAux.VdbeDelete(ref pParse.pVdbe);
                pParse.pVdbe = null;
            }
#if !SQLITE_OMIT_SHARED_CACHE
if ( pParse.nested == 0 )
{
MemPool.DbFree( db, ref pParse.aTableLock );
pParse.aTableLock = null;
pParse.nTableLock = 0;
}
#endif
#if !SQLITE_OMIT_VIRTUALTABLE
MemPool.DbFree(db,pParse.apVtabLock);
#endif
            if (!Const.IN_DECLARE_VTAB)
            {
                /* If the pParse.declareVtab flag is set, do not delete any table
        ** structure built up in pParse.pNewTable. The calling code (see vtab.c)
        ** will take responsibility for freeing the Table structure.
        */
               Build. DeleteTable(ref pParse.pNewTable);
            }

#if !SQLITE_OMIT_TRIGGER
            TriggerHelper.DeleteTrigger(db, ref pParse.pNewTrigger);
#endif
            MemPool.DbFree(db, ref pParse.apVarExpr);
            MemPool.DbFree(db, ref pParse.aAlias);
            while (pParse.pAinc != null)
            {
                AutoincInfo p = pParse.pAinc;
                pParse.pAinc = p.pNext;
                MemPool.DbFree(db, ref p);
            }
            while (pParse.pZombieTab != null)
            {
                Table p = pParse.pZombieTab;
                pParse.pZombieTab = p.pNextZombie;
                Build.DeleteTable(ref p);
            }
            if (nErr > 0 && pParse.rc == StatusCode.SQLITE_OK)
            {
                pParse.rc = StatusCode.SQLITE_ERROR;
            }
            return nErr;
        }
    }
}